

import ij.IJ;
import ij.ImagePlus;
import ij.gui.NewImage;
import ij.plugin.filter.PlugInFilter;
import ij.process.Blitter;
import ij.process.ImageProcessor;

import pluginUtils.Complexe; 

/**
 * 
 */

/**
 * @author Francesco
 *
 */
public class ExperimentalDroste_ implements PlugInFilter {
	private int imgCols; 
	private int imgRows;
	
	private double r1=0.2;
	private double r2=0.8; 
	
	
	/* (non-Javadoc)
	 * @see ij.plugin.filter.PlugInFilter#run(ij.process.ImageProcessor)
	 */
	public void run(ImageProcessor ip) {
		 //get width, height and the region of interest
			int w = ip.getWidth();     
			int h = ip.getHeight();  
			this.imgCols=w;
			this.imgRows=h;
			
			    
		

			// create a new image with the same size and copy the pixels of the original image
			ImagePlus inverted = NewImage.createRGBImage ("New image", w, h, 1, NewImage.FILL_BLACK);
			ImageProcessor inv_ip = inverted.getProcessor();
			inv_ip.copyBits(ip,0,0,Blitter.COPY);

			int[] basepixels = (int[]) inv_ip.getPixels();
			int[] pixels=new int[this.imgCols*this.imgRows];
			
			
			double alpha=Math.atan(Math.log(r2/r1)/(2*Math.PI));
			Complexe ialpha=Complexe.createComplexeFromRI(Math.cos(alpha),Math.sin(alpha)); 
			Complexe beta=Complexe.mulbyDouble(ialpha, Math.cos(alpha));
			Complexe invBeta=Complexe.inverse(beta); 
			Complexe coef=Complexe.power(Complexe.createComplexeFromRI(r2/r1,0),beta);  
			Complexe invcoef=Complexe.power(Complexe.createComplexeFromRI(r1/r2,0),beta);  
			
			    for(int xrow=0;xrow<imgRows;xrow++){
			    	for(int ycol=0;ycol<imgCols;ycol++){
			    		//System.out.println("boucle"); 
				    	// transform in [-1,1]x[-1,1]
			    		double x1,y1,X,Y;
			    		int newX,newY;
				    	double x0=(xrow+0.0)/imgRows*2.0-1.0;
				    	double y0=(ycol+0.0)/imgCols*2.0-1.0; 
				    	Complexe z=Complexe.createComplexeFromRI(x0,y0);
				    	double r=Math.sqrt(x0*x0+y0*y0);
				    	Complexe z2;
				    	if((r>r1)&&(r<r2)){
				    	z2=Complexe.mulbyDouble(z,r1/r2);
				    	z=Complexe.power(z2,beta);
				     
				    	
				    	x1=z.getReal(); 
				    	y1=z.getIm();
				    	
				    	
				    	X=imgRows/2*(1+x1);
				    	Y=imgCols/2*(1+y1); 
				    	newX=(int)X; 
				    	newY=(int)Y; 
				    	
				    	try{
				    		pixels[newX*imgCols+newY]=basepixels[xrow*imgCols+ycol];
				    	}
				    	catch(Exception e){System.err.println("Index out of bounds");}
				    	}
				    	if((r>r2)&&(r<(r2*r2/r1))){
				    		
				    		z2=Complexe.mulbyDouble(Complexe.createComplexeFromRI(x0,y0),r1/r2);
				    		z=Complexe.mul(z2,coef);
				    		z=Complexe.power(z2,invBeta);
				    		
				    		
				    		x1=z.getReal(); 
					    	y1=z.getIm();
					    	
					    	
					    	X=imgRows/2*(1+x1);
					    	Y=imgCols/2*(1+y1); 
					    	newX=(int)X; 
					    	newY=(int)Y; 
					    	
					    	try{
					    		pixels[newX*imgCols+newY]=basepixels[xrow*imgCols+ycol];
					    	}
					    	catch(Exception e){System.err.println("Index out of bounds");}
				    		
				    		
				    		
				    		
				    	}//if
				    	
				    	
				    	
			    	}
			    System.out.println("Row : "+xrow);
			    	
			 inv_ip.setPixels(pixels); 
			 inverted.show();
			 inverted.updateAndDraw();
			    	}
	}
	
			
	

	/* (non-Javadoc)
	 * @see ij.plugin.filter.PlugInFilter#setup(java.lang.String, ij.ImagePlus)
	 */
	
	public int setup(String arg, ImagePlus imp) {
		if (arg.equals("about"))
			{showAbout(); return DONE;}
	            return DOES_RGB+NO_CHANGES;

	}
	
	void showAbout() {
		IJ.showMessage("Droste effect",
			"Escher-like droste effect"
		); 

	}
}